﻿/*
* 作者:haojielyb
* 邮箱:haojielyb@qq.com
*/

using System.Buffers;
using System.Text;
using Furion;
using Furion.DependencyInjection;
using Furion.Logging;
using Lxb.Model;
using Lxb.Model.config;
using Lxb.Model.Service;
using MqttModel;
using MQTTnet;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using StackExchange.Redis;

namespace rfid9500_Mqtt
{
    public class OthMqttlxb
    {
        private static IMqttClient mqttClient;
        static String upload,
            path;
        static IServer rediserver;

        public static async void ConnectMqttServerAsync()
        {
            rediserver = RedisHelper.GetServer("127.0.0.1", 6379);
            var path = App.Configuration["facepath"]; // @"E:\weixin\FaceImage\";
            upload = App.Configuration["facepathupload"];
            try
            {
                StringLoggingPart.Default().SetMessage($"图片保存路径 {path}").LogWarning();

                //OthTool.Base64StringToImage(b64, $@"{path}/test.jpg");


                var factory = new MqttClientFactory();

                mqttClient = factory.CreateMqttClient();

                var mqt = App.GetConfig<MQTTSERVER>("MQTTSERVER");
                var options = new MqttClientOptionsBuilder()
                    .WithTcpServer(mqt.host, mqt.port)
                    .WithCredentials(mqt.user, mqt.pwd)
                    .WithClientId(Guid.NewGuid().ToString().Substring(0, 5))
                    .Build();

                mqttClient.ApplicationMessageReceivedAsync += (ReceiveMessage());

                //重连机制
                mqttClient.DisconnectedAsync += (
                    async e =>
                    {
                        Console.WriteLine("与服务器断开连接！");

                        StringLoggingPart
                            .Default()
                            .SetMessage($"连接服务器失败 Msg：{e}")
                            .LogError();

                        await Task.Delay(TimeSpan.FromSeconds(5));
                        try
                        {
                            await mqttClient.ConnectAsync(options);
                            Basetopic();
                        }
                        catch (Exception exp)
                        {
                            Console.Write($"重新连接服务器失败 Msg：{exp}");
                        }
                    }
                );

                await mqttClient.ConnectAsync(options);

                Console.Write("连接服务器成功！");
                StringLoggingPart.Default().SetMessage("连接服务器成功").LogWarning();
                Basetopic();
            }
            catch (Exception exp)
            {
                StringLoggingPart.Default().SetMessage($"连接服务器失败 Msg：{exp}").LogError();
                Console.Write($"连接服务器失败 Msg：{exp}");
            }
        }

        private static Func<MqttApplicationMessageReceivedEventArgs, Task> ReceiveMessage()
        {
            return async e =>
            {
                Scoped.Create(
                    async (factory, scope) =>
                    {
                        var services = scope.ServiceProvider;

                        DeviceService ds =
                            services.GetService(typeof(DeviceService)) as DeviceService;

                        OthUserService us =
                            services.GetService(typeof(OthUserService)) as OthUserService;
                        byte[] datein = e.ApplicationMessage.Payload.ToArray();
                        Console.WriteLine($"### {DateTime.Now.ToString()}收到信息 ###");
                        //Console.WriteLine($" Topic : {e.ApplicationMessage.Topic}");//主题
                        Console.WriteLine(" Payload: {0}\n", BitConverter.ToString(datein)); //页面信息
                        //Console.WriteLine($"+ QoS = {e.ApplicationMessage.QualityOfServiceLevel}");//消息等级
                        //Console.WriteLine($"+ Retain = {e.ApplicationMessage.Retain}");//是否保留
                        //Console.WriteLine();
                        var downdata = new SendModel();
                        var format = new IsoDateTimeConverter();
                        format.DateTimeFormat = "yyyy-MM-dd hh:mm:ss";
                        var kqs = App.GetService<Kaoqin_logService>();
                        var tops = e.ApplicationMessage.Topic.Split('/');
                        if (tops.Length != 3)
                        {
                            return;
                        }

                        if (tops[0].Equals("device") && tops[2].Equals("tag"))
                        {
                            if (datein.Length == 4)
                            {
                                Device wd = new Device();
                                wd.SN = tops[1];
                                wd.status = 1;
                                await ds.OnlineAsync(wd);
                            }
                            else
                            {
                                try
                                {
                                    var cardid = Jiexi.ParseAndPrintProtocol(datein);

                                    var auser = us.getUserByrfid(cardid);
                                    if (auser != null)
                                        await SaveLog(kqs, auser, tops[1]).ConfigureAwait(false);
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine(ex);
                                }
                            }
                        }
                    }
                );
                await Task.CompletedTask;
            };
        }

        static long oldstms = 0;

        private static async Task SaveLog(Kaoqin_logService kqs, Users u, string sn)
        {
            var now = DateTime.Now;
            var kqlog = new Kaoqin_log();
            kqlog.Id = u.user_id.ToString();
            kqlog.datep = now.ToString("yyyy/MM/dd");
            kqlog.timep = now.ToString("HH:mm:ss");
            kqlog.sn = sn;
            kqlog.name = u.username;
            kqlog.cdate = now;
            kqlog.time = now;
            kqlog.authority = "rfid9500";
            kqlog.scor = 100;

            try
            {
                QiniuTools.Catapic();

                kqlog.UID = QiniuTools.STMS.ToString();
                if (oldstms < QiniuTools.STMS)
                {
                    RedisHelper.LPUSH("qnk" + sn, kqlog.UID);
                    oldstms = QiniuTools.STMS;
                    Console.WriteLine("保存图片成功");
                }
            }
            catch (Exception exr)
            {

                Console.WriteLine($"文件保存失败：{exr.Message}");
                // StringLoggingPart.Default().SetMessage($"文件保存失败：{exr.Message}").LogError();
            }

            await kqs.AddAsync(kqlog).ConfigureAwait(false);
        }

        /// <summary>
        /// 基础订阅
        /// </summary>
        /// <returns></returns>
        public static void Basetopic()
        {
            Console.WriteLine("订阅主题");
            //  Subscribe(topics.heartbeat);
            //  Subscribe(topics.basic);
            Subscribe("device/5C5310A561BA/tag");

            /// Subscribe(topics.WechatMessage);
        }

        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="topicName"></param>
        private static async void Subscribe(string topicName)
        {
            string topic = topicName.Trim();
            if (string.IsNullOrEmpty(topic))
            {
                Console.Write("订阅主题不能为空！");
                return;
            }

            Console.WriteLine("订阅主题" + topicName);
            if (!mqttClient.IsConnected)
            {
                Console.Write("MQTT客户端尚未连接！");
                return;
            }
            try
            {
                await mqttClient.SubscribeAsync(
                    new MqttTopicFilterBuilder().WithTopic(topic).Build()
                );
            }
            catch (Exception e)
            {
                StringLoggingPart
                    .Default()
                    .SetMessage($"订阅 {topicName} 异常" + e.Message)
                    .LogWarning();
                throw;
            }
        }

        /// <summary>
        /// 取消订阅
        /// </summary>
        /// <param name="topicName"></param>
        private static async void Unsubscribe(string topicName)
        {
            string topic = topicName.Trim();
            if (string.IsNullOrEmpty(topic))
            {
                Console.Write("取消订阅主题不能为空！");
                return;
            }

            if (!mqttClient.IsConnected)
            {
                Console.Write("MQTT客户端尚未连接！");
                return;
            }
            await mqttClient.UnsubscribeAsync(topic);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message"></param>
        private static async void Publish(string topicName, string message)
        {
            string topic = topicName.Trim();
            string msg = message.Trim();

            if (string.IsNullOrEmpty(topic))
            {
                //  Console.Write("主题不能为空！");
                return;
            }
            if (!mqttClient.IsConnected)
            {
                // Console.Write("MQTT客户端尚未连接！");
                return;
            }

            //  Console.WriteLine("发布" + topic);
            //    Console.WriteLine( DateTime.Now.ToString()+ "发布msg" + msg);
            var MessageBuilder = new MqttApplicationMessageBuilder()
                .WithTopic(topic)
                .WithPayload(msg)
                .WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce)
                .WithRetainFlag()
                .Build();

            await mqttClient.PublishAsync(MessageBuilder);
        }
    }

    public class MqttLinkStat
    {
        public MqttLinkStat()
        {
            live = 10;
            dt = DateTime.Now;
        }

        public int live { get; set; }
        public DateTime dt { get; set; }
    }
}
